#include "stm32f10x.h"                  // Device header
#include "Delay.h"


/*
@brief: 设置SCL总线的高低电平
@param: 高/低
@revtal: 无
*/
void myI2C_SCL_W(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
	Delay_us(10); 
}

/*
@brief: 设置SDA总线的高低电平
@param: 高/低
@revtal: 无
*/
void myI2C_SDA_W(uint8_t BitValue)
{
	GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
	Delay_us(10); 
}

/*
@brief: 读取SDA总线上的数据
@param: 无
@revtal: 读取的数据
*/
uint8_t myI2C_SDA_R(void)
{
	uint8_t BitValue;
	BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
	Delay_us(10);
	return BitValue;
}


/*
@brief: 软件I2C协议初始化, 选择SCL, SDA对应的引脚, 并进行初始化配置
@param: 无
@revtal: 无
*/
void myI2C_Init(void)
{
	// 开启时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);		//开启GPIOA的时钟
	
	/*GPIO初始化*/
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;			// SCL/SDA 初始化为开漏输出模式
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOB, &GPIO_InitStructure);						// 将PB10和PB11引脚初始化为开漏输出
	
	/*设置GPIO初始化后的默认电平*/
	GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11);				//设置SCL/SDA 置高电平(释放总线, 此时SCL和SDA处于空闲状态)
}

/*
@brief: 软件编写I2C时序的起始时序单元
@param: 无
@revtal: 无
*/
void myI2C_Start(void)
{
	// 起始条件的执行逻辑, 注意兼容重复起始的逻辑条件, 所以我们先释放SDA
	myI2C_SDA_W(1);
	myI2C_SCL_W(1);
	myI2C_SDA_W(0);
	myI2C_SCL_W(0);
}

/*
@brief: 软件编写I2C时序的停止时序单元
@param: 无
@revtal: 无
*/
void myI2C_Stop(void)
{
	// 先拉低SDA, 再释放SCL, SDA, 确保SDA产生一个上升沿
	myI2C_SDA_W(0);
	myI2C_SCL_W(1);
	myI2C_SDA_W(1);
}

/*
@brief: 软件编写I2C时序的发送字节时序单元
@param: 要发送到SDA的字节数据
@revtal: 无
*/
void myI2C_SendByte(uint8_t Byte)
{
	uint8_t i;
	for (i = 0; i < 8; i ++)
	{
		myI2C_SDA_W(Byte & (0x80 >> i));		// 高位先行
		myI2C_SCL_W(1);					// 释放SCL, 为放下一个数据做准备, 尽快从SDA上拿走数据
		myI2C_SCL_W(0);
	}
}

/*
@brief: 软件编写I2C时序的读取字节时序单元
@param: 无
@revtal: 读取到的数据
*/
uint8_t myI2C_ReceiveByte(void)
{
	uint8_t i, Byte = 0x00;
	myI2C_SDA_W(1);				// 释放SDA(控制权)
	for (i = 0; i < 8; i ++)
	{
		myI2C_SCL_W(1);				// SCL高可读
		if (myI2C_SDA_R() == 1) {Byte |= (0x80 >> i);}
		myI2C_SCL_W(0);				// SCL低可写
	}
	return Byte;
}

/*
@brief: 软件编写I2C时序的发送应答时序单元
@param: 要发送到SDA的应答数据
@revtal: 无
*/
void myI2C_SendAck(uint8_t AskBit)
{
//	myI2C_SDA_W(1);					// 释放SDA,  这一行代码可以省去, 因为 "线与"
	myI2C_SDA_W(AskBit);			// 应答放入SDA
	myI2C_SCL_W(1);					// 读取应答
//	myI2C_SDA_W(1);					// 释放SDA(控制权)
	myI2C_SCL_W(0);					// SCL低, 进入下一个时序单元
}

/*
@brief: 软件编写I2C时序的接收应答时序单元
@param: 无
@revtal: 读取到的应答
*/
uint8_t myI2C_ReceiveAck(void)
{
	uint8_t AskBit;
	myI2C_SDA_W(1);				// 释放SDA(控制权)
	myI2C_SCL_W(1);				// SCL高可读
	AskBit = myI2C_SDA_R();
	myI2C_SCL_W(0);				// SCL低可写, 进入下一个时序单元
	return AskBit;
}
